﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace WindowsGame1
{
    public class Tile
    {
        static public int width = 501;
        static public int height = 501;


        public float[,] heightData;
        public VertexPositionColor[] vertices;
        public int[] indices;
        public bool terrainLoaded = false;

        VertexBuffer myVertexBuffer;
        IndexBuffer myIndexBuffer;

        public void SetUpVertices()
        {
            vertices = new VertexPositionColor[(Tile.width) * (Tile.height)];
            for (int x = 0; x < Tile.width; x++)
            {
                for (int y = 0; y < Tile.height; y++)
                {
                    vertices[x + (y * Tile.width)].Position = new Vector3((float)(x) * World.scale, heightData[x, y] * World.scale/5, (float)(y) * World.scale);

                    int kolorr = 255 - (int)Math.Abs(3 * (heightData[x, y] - 110)); if (kolorr < 0) kolorr = 0; if (kolorr > 255) kolorr = 255;
                    int kolorg = (255 - (int)Math.Abs(3 * (heightData[x, y] - 70))) + (255 - (int)Math.Abs(6 * (heightData[x, y] - 10))); if (kolorg < 0) kolorg = 0; if (kolorg > 255) kolorg = 255;
                    int kolorb = 255 - (int)Math.Abs(6 * (heightData[x, y] + 20)); if (kolorb < 0) kolorb = 0; if (kolorb > 255) kolorb = 255;
                    Color kolor = new Color(kolorr, kolorg, kolorb);
                    vertices[x + (y * Tile.width)].Color = kolor;
                }
            }
        }

        public void SetUpIndices()
        {
            indices = new int[(Tile.width-1) * (Tile.height-1) * 6];
            int counter = 0;
            for (int y = 0; y < Tile.height-1; y++)
            {
                for (int x = 0; x < Tile.width-1; x++)
                {
                    int lowerLeft = x + y * Tile.width;
                    int lowerRight = (x + 1) + y * Tile.width;
                    int topLeft = x + (y + 1) * Tile.width;
                    int topRight = (x + 1) + (y + 1) * Tile.width;

                    indices[counter++] = topLeft;
                    indices[counter++] = lowerRight;
                    indices[counter++] = lowerLeft;

                    indices[counter++] = topLeft;
                    indices[counter++] = topRight;
                    indices[counter++] = lowerRight;
                }
            }
        }

        public void CopyToBuffers()
        {
            myVertexBuffer = new VertexBuffer(Game1.device, VertexPositionColor.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
            myVertexBuffer.SetData(vertices);

            myIndexBuffer = new IndexBuffer(Game1.device, typeof(int), indices.Length, BufferUsage.WriteOnly);
            myIndexBuffer.SetData(indices);

            terrainLoaded = true;
        }

        public void renderuj(int lod)
        {
            if (terrainLoaded)
            {
                switch(lod)
                {
                    case 0: case 1: case 2:
                        Game1.device.Indices = myIndexBuffer;
                        Game1.device.SetVertexBuffer(myVertexBuffer);
                        Game1.device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertices.Length, 0, indices.Length / 3);
                        break;
                    default:
                        VertexPositionColor[] points = new VertexPositionColor[4];
                        points[0] = new VertexPositionColor(new Vector3(0, 0, 0), Color.Black);
                        points[1] = new VertexPositionColor(new Vector3(Tile.width*World.scale, 0, 0), Color.Black);
                        points[2] = new VertexPositionColor(new Vector3(Tile.width*World.scale, 0, Tile.height*World.scale), Color.Black);
                        points[3] = new VertexPositionColor(new Vector3(0, 0, Tile.height*World.scale), Color.Black);

                        short[] lines = new short[8];
                        lines[0] = 0; lines[1] = 1;
                        lines[2] = 1; lines[3] = 2;
                        lines[4] = 2; lines[5] = 3;
                        lines[6] = 3; lines[7] = 0;

                        Game1.device.DrawUserIndexedPrimitives<VertexPositionColor>(
                            PrimitiveType.LineList, points, 0, 4, lines, 0, 4);
                        break;
                }
            }

        }

        ///////////////////////
        //Funkcje statyczne
        public static void LoadMap(string name, ref int tilesx, ref int tilesy, ref Tile[,] tiles)
        {
            int mapx, mapy;
            int terrainWidth = 500;
            int terrainHeight = 500;
            float[,] heightData;

            Console.WriteLine("wczytam mape");
            int ii;

            MemoryStream bytedc = new MemoryStream();
            FileStream inFile;
            try
            {
                inFile = new FileStream(name, FileMode.Open, FileAccess.Read);
            }
            catch
            {
                throw;
            }

            byte[] data = new byte[inFile.Length];
            ii = inFile.Read(data, 0, data.Length);
            Console.WriteLine("odczytano " + ii);
            int ibufor = 0;

            // odczytanie danych

            string sh = "ncols";
            ibufor = FparseXML.szukajsekcji(sh, data, ibufor);
            Console.WriteLine("znaleziono sekcje " + sh + " na " + ibufor);
            mapx = (int)FparseXML.parsujr(data, ref ibufor);
            Console.WriteLine("wartosc to " + mapx);

            sh = "nrows";
            ibufor = FparseXML.szukajsekcji(sh, data, ibufor);
            Console.WriteLine("znaleziono sekcje " + sh + " na " + ibufor);
            mapy = (int)FparseXML.parsujr(data, ref ibufor);
            Console.WriteLine("wartosc to " + mapy);

            sh = "xllcorner";
            ibufor = FparseXML.szukajsekcji(sh, data, ibufor);
            Console.WriteLine("znaleziono sekcje " + sh + " na " + ibufor);
            Console.WriteLine("wartosc to " + FparseXML.parsujr(data, ref ibufor));

            sh = "yllcorner";
            ibufor = FparseXML.szukajsekcji(sh, data, ibufor);
            Console.WriteLine("znaleziono sekcje " + sh + " na " + ibufor);
            Console.WriteLine("wartosc to " + FparseXML.parsujr(data, ref ibufor));

            sh = "cellsize";
            ibufor = FparseXML.szukajsekcji(sh, data, ibufor);
            Console.WriteLine("znaleziono sekcje " + sh + " na " + ibufor);
            Console.WriteLine("wartosc to " + FparseXML.parsujr(data, ref ibufor));

            sh = "NODATA_value";
            ibufor = FparseXML.szukajsekcji(sh, data, ibufor);
            Console.WriteLine("znaleziono sekcje " + sh + " na " + ibufor);
            Console.WriteLine("wartosc to " + FparseXML.parsujr(data, ref ibufor));

            terrainWidth = mapx;
            terrainHeight = mapy;

            Console.WriteLine("mam odczytac " + mapx * mapy);

            int count = 0;
            heightData = new float[terrainWidth, terrainHeight];
            for (int y = 0; y < terrainHeight; y++)
            {
                for (int x = 0; x < terrainWidth; x++)
                {
                    heightData[x, y] = FparseXML.parsujr(data, ref ibufor);
                    if (heightData[x, y] == -9999) heightData[x, y] = 0;
                    count++;
                }
            }

            // Utworzenie kawalkow terenu
            tilesx = mapx / Tile.width;
            tilesy = mapy / Tile.height;

            Console.WriteLine("podzielono na " + tilesx + " x " + tilesy);

            tiles = new Tile[tilesx, tilesy];

            for (int i = 0; i < tilesx; i++)
            {
                for (int j = 0; j < tilesy; j++)
                {
                    tiles[i, j] = new Tile();
                    tiles[i, j].heightData = new float[Tile.width, Tile.height];
                    ////////////////////////////////////
                    for (int y = 0; y < Tile.height; y++)
                    {
                        for (int x = 0; x < Tile.width; x++)
                        {
                            try
                            {
                                tiles[i, j].heightData[x, y] = heightData[x + i * (Tile.width - 1), y + j * (Tile.height - 1)];
                            }
                            catch
                            {
                                tiles[i, j].heightData[x, y] = 0;
                            }
                        }
                    }
                }

            }
        }
    }
}
